﻿using System;
using System.Collections.Generic;

namespace Ruandao.MiniAccess
{

    /// <summary>
    /// 实体类的泛型基类。
    /// </summary>
    /// <typeparam name="T">实体基类的具体实现类。</typeparam>
    /// <remarks>
    /// </remarks>
    public abstract class EntityBase<T> where T: EntityBase<T>,new()
    {
        /// <summary>
        /// 默认构造，设置实体的状态为EntityStateType.NewCreate。
        /// </summary>
        /// <param name="access">
        /// </param>
        public EntityBase(AccessBase access)
        {
            this.isNew = true ;
            this.isDelete = false;
            this.oldPropertyValues = new Dictionary<string, object>();
            this.access = access;
        }

        AccessBase access;

        bool isNew;
        /// <summary>
        /// 
        /// </summary>
        public bool IsNew
        {
            get { return isNew; }
            set { isNew = value; }
        }

        bool isDelete;
        /// <summary>
        /// 
        /// </summary>
        public bool IsDelete
        {
            get { return isDelete; }
            set { isDelete = value; }
        }

        /// <summary>
        /// 保存实体。根据实体的状态，自动选择执行Delete/Update/Insert三个方法之一
        /// <br/>异常：OrMapException(发生SqlException异常，或者没有完成修改和删除的功能。)
        /// </summary>
        public virtual int Save()
        {
            if (isNew && (!isDelete))
            {
                isNew = false;
                return access.InsertEntity((T)this);
            }

            TableMap tableMap = access.GetTableMap(typeof(T));
            if (tableMap.GetKeyPropertyNames().Length == 0)
            {
                throw new OrMapException("EntityBase基类中的Delete和Update实现不支持无主键的数据表");
            }

            if ( isDelete )
            {
                isNew = true;
                oldPropertyValues.Clear();
                return access.DeleteEntity<T>(this.GetOldKeyValues(tableMap)); 
            }
            else if ( (!isDelete) && oldPropertyValues.Count > 0 )
            {
                oldPropertyValues.Clear();
                return access.UpdateEntity<T>((T)this, this.GetOldKeyValues(tableMap));
            }
            return 0;  //没有需要保存的数据。
        }

        IDictionary<string, object> oldPropertyValues;
        /// <summary>
        /// 只读。
        /// </summary>
        IDictionary<string, object> OldPropertyValues
        {
            get
            {
                return this.oldPropertyValues;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="property"></param>
        /// <param name="value"></param>
        protected void ChangePropertyValue(string property, object value)
        {
            if (oldPropertyValues.ContainsKey(property))
            {
                if (oldPropertyValues[property] == value)
                {
                    oldPropertyValues.Remove(property);
                    return;
                }
            }

            // add new item or modify old item.
            oldPropertyValues[property] = value;
        }

        /// <summary>
        /// 得到当前实体的主键参数的原始值集合。
        /// </summary>
        /// <remarks>
        /// 如果属性已经被修改，则原来的值存在OldPropertyValues中，如果没有
        /// 修改则不保存。
        /// 注意：集合的顺序是很重要的，和存储过程中参数顺序一致。
        /// </remarks>
        protected object[] GetOldKeyValues(TableMap tableMap)
        {
            string[] names = tableMap.GetKeyPropertyNames();
            object[] values = new object[names.Length];

            Type t = typeof(T);
            for (int i = 0; i < names.Length; i++)
            {
                if ( oldPropertyValues.ContainsKey(names[i]) )
                {
                    values[i] = oldPropertyValues[names[i]];
                }
                else
                {
                    values[i] = t.GetProperty(names[i]).GetValue(this, null);
                }
            }
            return values;
        }

    }
}
